/* -*- c++ -*- */

#ifndef _TRIANGULO_H_
#define _TRIANGULO_H_
#include "defs.h"
#include "Punto.h"

#define TN1    0
#define TN2    1
#define TN3    2
#define TN123  3

class Triangulo {
 private:
  int _nodes[ TN123];
  int _num;
 public:
  Triangulo( int n1, int n2 = 0, int n3 = 0, int num = 0) {
    _nodes[ TN1] = n1;
    _nodes[ TN2] = n2;
    _nodes[ TN3] = n3;
    _num = num;
  };
  Triangulo( const Triangulo &tr) {
    _nodes[ TN1] = tr._nodes[ TN1];
    _nodes[ TN2] = tr._nodes[ TN2];
    _nodes[ TN3] = tr._nodes[ TN3];
    _num = tr._num;
  }
  Triangulo( void){};
  ~Triangulo() {};

  Triangulo &operator=( const Triangulo &tr) {
    _nodes[ TN1] = tr._nodes[ TN1];
    _nodes[ TN2] = tr._nodes[ TN2];
    _nodes[ TN3] = tr._nodes[ TN3];
    _num = tr._num;
    return *this;
  }
  
  void set( int n1, int n2 = 0, int n3 = 0, int num = 0) {
    _nodes[ TN1] = n1;
    _nodes[ TN2] = n2;
    _nodes[ TN3] = n3;
    _num = num;
  };
  void add_num( int num) {
    _num += num;
  }
  int get_num() const { return _num;}
  void set_num( int num) {
    _num = num;
  }

  int v1( void) const { return _nodes[ TN1];}
  int v2( void) const { return _nodes[ TN2];}
  int v3( void) const { return _nodes[ TN3];}
  int v( int idx) const { return _nodes[ idx];}
  int num( void) const { return _num;}

  int vmin( void) const {
    int ret = _nodes[ TN1];
    if ( _nodes[ TN2] < ret) ret = _nodes[ TN2];
    if ( _nodes[ TN3] < ret) ret = _nodes[ TN3];
    return ret;
  }

  int vmed( void) const {
    if ( _nodes[ TN1] < _nodes[ TN2]) {
      if ( _nodes[ TN2] < _nodes[ TN3]) {
        return _nodes[ TN2];
      } else {
        if ( _nodes[ TN1] < _nodes[ TN3]) {
          return _nodes[ TN3];
        } else {
          return _nodes[ TN1];
        }
      }
    } else {
      if ( _nodes[ TN2] >= _nodes[ TN3]) {
        return _nodes[ TN2];
      } else {
        if ( _nodes[ TN1] < _nodes[ TN3]) {
          return _nodes[ TN1];
        } else {
          return _nodes[ TN3];
        }
      }
    }
  }
  
  int vmax( void) const {
    int ret = _nodes[ TN1];
    if ( _nodes[ TN2] > ret) ret = _nodes[ TN2];
    if ( _nodes[ TN3] > ret) ret = _nodes[ TN3];
    return ret;
  }

  Punto get_normal( const Punto *coords) const {
    Punto normal;
    Punto u, v;
    u = coords[ _nodes[ TN2]] - coords[ _nodes[ TN1]];
    v = coords[ _nodes[ TN3]] - coords[ _nodes[ TN1]];
    double x = u.y() * v.z() - u.z() * v.y();
    double y = u.z() * v.x() - u.x() * v.z();
    double z = u.x() * v.y() - u.y() * v.x();
    normal.set( ( float)x, ( float)y, ( float)z);
    normal.normalize();
    return normal;
  }

  void swap_sense() {
    int tmp = _nodes[ TN2];
    _nodes[ TN2] = _nodes[ TN3];
    _nodes[ TN3] = tmp;
  }
  

  void get_plane( const Punto *coords, float &a, float &b, float &c, float &d) const {
    Punto normal = get_normal( coords);
    const Punto &p1 = coords[ _nodes[ TN1]];
    // float dd = - ( normal * p1);
    float dd = - scalar_product( normal, p1);
    a = normal.x();
    b = normal.y();
    c = normal.z();
    d = dd;
  }

  float get_plane( const Punto *coords, Punto &v) {
    v = get_normal( coords);
    const Punto &p1 = coords[ _nodes[ TN1]];
    // float dd = - ( v * p1);
    float dd = - scalar_product( v, p1);
    return dd;
  }

  int esta_colapsado( void) const {
    return ( _nodes[ TN1] == _nodes[ TN2]) || ( _nodes[ TN1] == _nodes[ TN3]) || ( _nodes[ TN2] == _nodes[ TN3]);
  }
  
  int no_esta_colapsado( void) const {
    return ( _nodes[ TN1] != _nodes[ TN2]) && ( _nodes[ TN1] != _nodes[ TN3]) && ( _nodes[ TN2] != _nodes[ TN3]);
  }
};

inline int qsort_triang_min_med_max( const void *v1, const void *v2) {
  Triangulo *t1 = ( Triangulo *)v1;
  Triangulo *t2 = ( Triangulo *)v2;
  int dif = t1->vmin() - t2->vmin();
  if ( !dif) {
    dif = t1->vmed() - t2->vmed();
    if ( !dif) {
      dif = t1->vmax() - t2->vmax();
    }
  }
  return ( dif > 0) - ( dif < 0); // -1, 0 or +1
}

inline int qsort_triang_n1_n2_n3( const void *v1, const void *v2) {
  Triangulo *t1 = ( Triangulo *)v1;
  Triangulo *t2 = ( Triangulo *)v2;
  int dif = t1->v1() - t2->v1();
  if ( !dif) {
    dif = t1->v2() - t2->v2();
    if ( !dif) {
      dif = t1->v3() - t2->v3();
    }
  }
  return ( dif > 0) - ( dif < 0); // -1, 0 or +1
}

inline bool equal_sorted_nodes( const Triangulo &t1, const Triangulo &t2) {
  return ( t1.vmin() == t2.vmin()) && ( t1.vmed() == t2.vmed()) && ( t1.vmax() == t2.vmax());
}

#endif // _TRIANGULO_H_
